package com.ccp.dev.workflow.service.bpm.thread;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;
import javax.naming.Context;

import com.ccp.dev.core.basic.engine.IScript;
import com.ccp.dev.core.basic.util.ContextUtil;
import com.ccp.dev.core.util.BeanUtils;
import com.ccp.dev.core.util.StringUtil;
import com.ccp.dev.workflow.bpmconst.BpmConst;
import com.ccp.dev.workflow.bpmutil.BpmUtil;
import com.ccp.dev.workflow.dao.ActDefModelDao;
import com.ccp.dev.workflow.model.bpm.TaskExecutor;
import com.ccp.dev.workflow.service.BpmNodeUserService;
import org.flowable.bpmn.model.Activity;
import org.flowable.bpmn.model.MultiInstanceLoopCharacteristics;
import org.flowable.engine.delegate.DelegateExecution;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;




/**
 * 流程任务人员分配处理类
 * @version 2019-07-18
 *
 */
@Service
public class TaskUserAssignService implements IScript {
	
	private Logger logger=LoggerFactory.getLogger(TaskUserAssignService.class);
	/**
	 * 目标节点人员授权绑定 里面存的值为nodeId,List userIds。
	 */
	private static ThreadLocal<Map<String,List<TaskExecutor>>> nodeUserMapLocal=new ThreadLocal<Map<String,List<TaskExecutor>>>();
	/**
	 * 表单用户,节点未设置人员时获取该用户列表（所有后续节点用户相同）
	 */
	private static ThreadLocal<List<TaskExecutor>> formUsers=new ThreadLocal<List<TaskExecutor>>();
	/**
	 * 任务执行人。
	 */
	private static ThreadLocal<List<TaskExecutor>> taskExecutors=new ThreadLocal<List<TaskExecutor>>();
	
	
	@Resource
	private BpmNodeUserService bpmNodeUserService;
	
	@Resource
	private ActDefModelDao actDefModelDao;
	
	


	/**
	 * 动态设置下一步节点的执行人。
	 * <pre>
	 * 	可以设置多个节点，每一个节点对应一组人的ID。
	 *  节点数组大小和人员的数组大小必须一致，人员的id使用逗号分隔。
	 * </pre>
	 * @param map
	 *
	 */
	public void setNodeUser(Map<String,List< TaskExecutor>> map){
		nodeUserMapLocal.set(map);
	}
	
	/**
	 * 添加节点人员。
	 * @param nodeId
	 * @param executors
	 */
	public void addNodeUser(String nodeId,List<TaskExecutor> executors){
		if(BeanUtils.isEmpty(executors)){
			return;
		}
	
		Map<String,List<TaskExecutor>> nodeUserMap=nodeUserMapLocal.get();
		if(nodeUserMap==null){
			nodeUserMap=new HashMap<String,List<TaskExecutor>>();
		}
		nodeUserMap.remove(nodeId);
		nodeUserMap.put(nodeId, executors);
		nodeUserMapLocal.set(nodeUserMap);
	}
	
	/**
	 * 设置某个节点的执行人。
	 * @param nodeId	节点ID。
	 * @param userIds	节点人员使用逗号进行分隔。
	 */
	public void addNodeUser(String nodeId,String userIds){
        if (StringUtil.isEmpty(userIds)) {
            return;
        }
		List<TaskExecutor> executorList= BpmUtil.getTaskExecutors(userIds);
		addNodeUser(nodeId,executorList);	
	}
	
	/**
	 * 添加节点用户。
	 * @param aryNodeId
	 * @param aryUserIds
	 */
	public void addNodeUser(String[] aryNodeId,String[] aryUserIds){
		if(BeanUtils.isEmpty(aryUserIds)){
			return;
		}
		Map<String,List<TaskExecutor>> nodeUserMap=nodeUserMapLocal.get();
		if(nodeUserMap==null){
			nodeUserMap=new HashMap<String,List<TaskExecutor>>();
		}
		for(int i=0;i<aryNodeId.length;i++){
			String nodeId=aryNodeId[i];
			String userIds=aryUserIds[i];
			if(StringUtil.isEmpty(userIds)){
				continue;
			}
		
			List<TaskExecutor> executorList=BpmUtil.getTaskExecutors(userIds);
			nodeUserMap.put(nodeId, executorList);
		}
		nodeUserMapLocal.set(nodeUserMap);
	}
	
	
	public Map<String,List<TaskExecutor>> getNodeUserMap(){
		return nodeUserMapLocal.get();
	}
	
	public  void clearNodeUserMap(){
		nodeUserMapLocal.remove();
	}

	
	/**
	 * 设置的任务执行人。
	 * @param users		用户ID使用逗号分隔。
	 */
	public void setExecutors(String users){
		if(StringUtil.isEmpty(users)){
			return ;
		}
		String[] aryUsers=users.split(",");
		List<TaskExecutor> list=new ArrayList<TaskExecutor>();
		for(String userId:aryUsers){
			TaskExecutor executor=new TaskExecutor(userId);
			list.add(executor);
		}
		taskExecutors.set(list);
	}

	/**
	 * 设置设置任务执行人。
	 * @param users		设置任务执行人。
	 */
	public void setExecutors(List<TaskExecutor> users) {
		taskExecutors.set(users);
	}
	
	/**
	 * 获取任务执行人。
	 * @return
	 */
	public List<TaskExecutor> getExecutors() {
		return taskExecutors.get(); 
	}
	
	/**
	 * 清除执行人。
	 */
	public void clearExecutors() {
		taskExecutors.remove();
	}
	

	
	/**
	 * 清除所有的线程变量。
	 */
	public static void clearAll(){
		formUsers.remove();
		taskExecutors.remove();
		nodeUserMapLocal.remove();
	}

    /**
     * 获取会签用户，用于会签节点。
     * <pre>
     * 在流程定义中
     * &lt;xsl:attribute name="activiti:collection">${taskUserAssignService.getSignUser(execution)}&lt;/xsl:attribute
     * 1.从上下文指定的用户中获取会签用户。
     * 2.如果获取不到，并且该节点是串行会签的节点，则从会签数据表当中获取。
     * 3.如果再获取不到，那么则从节点配置的数据库中获取用户数据。
     * </pre>
     * @param execution 运行实例
     * @return
     */
	public List<TaskExecutor> getSignUser(DelegateExecution execution) {
        String nodeId = execution.getCurrentActivityId();
        MultiInstanceLoopCharacteristics loopCharacteristics = ((Activity) execution.getCurrentFlowElement()).getLoopCharacteristics();
        boolean sequential = loopCharacteristics.isSequential();

        List<TaskExecutor> users = null;
        String varName = nodeId + "_" + BpmConst.SIGN_USERIDS;
        // 串行会签人员首先从流程变量中获取
        if (sequential) {
            users = (List<TaskExecutor>) execution.getVariable(varName);
            if (BeanUtils.isNotEmpty(users)) {
                return users;
            }
        }

        Map<String, List<TaskExecutor>> nodeUserMap = nodeUserMapLocal.get();

        // 会签任务用户来自前台的用户选择
        if (nodeUserMap != null && BeanUtils.isNotEmpty(nodeUserMap.get(nodeId))) {
            users = nodeUserMap.get(nodeId);
            saveExecutorVar(execution, users);
            return users;
        }

        // 从上下问中获取
        users = getExecutors();

        if (BeanUtils.isNotEmpty(users)) {
            saveExecutorVar(execution, users);
            addNodeUser(nodeId, users);
            return users;
        }

        //从数据库配置中获取
        String procDefId = execution.getProcessDefinitionId();
        // 获取发起用户
        String procInstId = execution.getProcessInstanceId();
        Map<String, Object> variables = execution.getVariables();
        String startUserId = variables.get(BpmConst.StartUser).toString();
        String preTaskUser = ContextUtil.getCurrentUserId();
        List<TaskExecutor> exeUserIds = bpmNodeUserService.getExeUserIds(procDefId, procInstId, nodeId, startUserId, preTaskUser, variables);

        if (BeanUtils.isNotEmpty(exeUserIds)) {
            saveExecutorVar(execution, exeUserIds);
        }
        addNodeUser(nodeId, exeUserIds);
        return exeUserIds;
    }

    /**
     * 将用户列表添加到流程变量
     * @param execution 运行实例
     * @param users 用户列表
     */
    private void saveExecutorVar(DelegateExecution execution, List<TaskExecutor> users) {
        MultiInstanceLoopCharacteristics loopCharacteristics = ((Activity) execution.getCurrentFlowElement()).getLoopCharacteristics();
        boolean sequential = loopCharacteristics.isSequential();
        if (sequential) {
            String nodeId = execution.getCurrentActivityId();
            String varName = nodeId + "_" + BpmConst.SIGN_USERIDS;
            execution.setVariable(varName, users);
        }
    }
}
